﻿using System;
using System.Drawing;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using Excel.Expressions.Classes;

namespace Excel.Application
{
    public partial class Main : Form
    {
        private Core _core = new Core();

        public Main()
        {
            InitializeComponent();

            this.DoubleBuffered = true;
            this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true);

            typeof(DataGridView).InvokeMember("SetStyle", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, dataGridView1, new object[] { ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true });
            typeof(DataGridView).InvokeMember("DoubleBuffered", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, null, dataGridView1, new object[] { true });

            this.dataGridView1.Dock = DockStyle.Fill;
            this.dataGridView1.RowCount = 256;
            this.dataGridView1.ColumnCount = 256;
            this.dataGridView1.VirtualMode = true;
            this.dataGridView1.AllowUserToResizeColumns = false;
            this.dataGridView1.AllowUserToResizeRows = false;
            this.dataGridView1.MultiSelect = false;
            this.dataGridView1.EditMode = DataGridViewEditMode.EditOnKeystrokeOrF2;
            this.dataGridView1.AllowUserToAddRows = false;
            this.dataGridView1.AllowUserToOrderColumns = false;
            this.dataGridView1.SelectionMode = DataGridViewSelectionMode.CellSelect;
            this.dataGridView1.CellValueNeeded += new DataGridViewCellValueEventHandler(dataGridView1_CellValueNeeded);
            this.dataGridView1.CellFormatting += new DataGridViewCellFormattingEventHandler(dataGridView1_CellFormatting);
            this.dataGridView1.SelectionChanged += new EventHandler(dataGridView1_SelectionChanged);
            this.dataGridView1.CellToolTipTextNeeded += new DataGridViewCellToolTipTextNeededEventHandler(dataGridView1_CellToolTipTextNeeded);
            this.textBox1.GotFocus += new EventHandler(textBox1_GotFocus);
            this.textBox1.LostFocus += new EventHandler(textBox1_LostFocus);

            this.openToolStripButton.Click += (e, args) => _core.LoadFromFile();
            this.saveToolStripButton.Click += (e, args) => _core.SaveToFile();
            this.openToolStripMenuItem.Click += (e, args) => _core.LoadFromFile();
            this.saveToolStripMenuItem.Click += (e, args) => _core.SaveToFile();

            this.newToolStripButton.Click += (e, args) => _core.Clear();
            this.newToolStripMenuItem.Click += (e, args) => _core.Clear();
            this.exitToolStripMenuItem.Click += (e, args) => Close();

            this.dataGridView1.RowHeadersWidth = 65;
            for (int i = 0; i < 256; i++)
            {
                this.dataGridView1.Columns[i].HeaderCell = new Column();
            }
            for (int j = 0; j < 255; j++)
            {
                this.dataGridView1.Rows[j].HeaderCell = new Row();
            }
            _core.Main = this;
            _core.GridView = dataGridView1;
            _core.TextView = textBox1;
            _core.OpenDialog = openFileDialog1;
            _core.SaveDialog = saveFileDialog1;
            _core.ErrorProvider = errorProvider1;
        }

        private class Row : DataGridViewRowHeaderCell
        {
            private static Font _font = new Font(FontFamily.GenericSansSerif, 8.0f, FontStyle.Regular);
            private static Brush _brush = new SolidBrush(Color.Black);
            private static StringFormat _format = new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
            protected override void Paint(System.Drawing.Graphics graphics, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
            {
                base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
                graphics.DrawString(Cell.GetRow(RowIndex), _font, _brush, cellBounds, _format);
            }
        }

        private class Column : DataGridViewColumnHeaderCell
        {
            private static Font _font = new Font(FontFamily.GenericSansSerif, 8.0f, FontStyle.Regular);
            private static Brush _brush = new SolidBrush(Color.Black);
            private static StringFormat _format = new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
            protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates dataGridViewElementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
            {
                base.Paint(graphics, clipBounds, cellBounds, rowIndex, dataGridViewElementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
                graphics.DrawString(Cell.GetCol(ColumnIndex), _font, _brush, cellBounds, _format);
            }
        }

        void textBox1_GotFocus(object sender, EventArgs e)
        {
            this.textBox1.TextChanged += new EventHandler(textBox1_TextChanged);
        }

        void textBox1_LostFocus(object sender, EventArgs e)
        {
            this.textBox1.TextChanged -= new EventHandler(textBox1_TextChanged);
        }

        void textBox1_TextChanged(object sender, EventArgs e)
        {
            _core.Validate();
        }

        void dataGridView1_CellToolTipTextNeeded(object sender, DataGridViewCellToolTipTextNeededEventArgs e)
        {
            if (e.RowIndex >= 0 && e.RowIndex <= 256 && e.ColumnIndex >= 0 && e.ColumnIndex <= 256)
            {
                Cell cell = Cell.GetCell(e.RowIndex, e.ColumnIndex);
                if (cell != null)
                {
                    if (cell.Expression != null)
                    {
#if DEBUG
                        e.ToolTipText = Format(string.Format("{0} : {1} = {2}", cell, cell.Expression, cell.Value));
#else
                        e.ToolTipText = Format(cell.Text);
#endif
                    }
                    else
                    {
                        e.ToolTipText = null;
                    }
                }
            }
        }

        private string Format(string p)
        {
            int counter = 0;
            StringBuilder sb = new StringBuilder();
            foreach (char ch in p)
            {
                if (++counter % 64 == 0)
                {
                    sb.Append(Environment.NewLine);
                }
                sb.Append(ch);
            }
            return sb.ToString();
        }

        void dataGridView1_SelectionChanged(object sender, EventArgs e)
        {
            DataGridViewCell cell = dataGridView1.SelectedCells[0];
            if (cell != null)
            {
                _core.Current = cell.Value as Cell;
                if (_core.Current == null || _core.Current.Expression == null)
                {
                    textBox1.Text = null;
                }
                else
                {
                    textBox1.Text = _core.Current.Text;
                }
            }
        }

        void dataGridView1_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
        {
            e.Value = Cell.GetCell(e.RowIndex, e.ColumnIndex);
        }

        void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            Cell current = e.Value as Cell;
            if (current != null)
            {
                e.Value = current.Value;
                e.FormattingApplied = true;
            }
        }
    }
}
